package com.cnbot.toolkit.file;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;

import com.cnbot.toolkit.stream.StreamUtil;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 *  @项目名：  ToolKitModel
 *  @包名：    com.cnbot.toolkit.file
 *  @文件名:   FileUtil
 *  @创建者:   ww
 *  @创建时间:  2019/11/13 9:41
 *  @描述：    文件读写工具类
 */
public final class FileUtil {

	private FileUtil() {}

	/**
	 * 删除指定路径的文件
	 * @param path
	 * @return
	 */
	public static boolean deleteFile(String path) {
		if (TextUtils.isEmpty(path)) {
			return false;
		}
		return deleteFile(new File(path));
	}

	/**
	 * 删除指定路径的文件
	 * @param file
	 * @return
	 */
	public static boolean deleteFile(File file) {
		if (file == null) {
			return false;
		}
		if (file.exists() && file.isFile()) {
			return file.delete();
		}
		return false;
	}

	/**
	 * 删除指定路径的文件或文件夹
	 * @param path
	 * @return
	 */
	public static boolean delete(String path) {
		if (TextUtils.isEmpty(path)) {
			return false;
		}
		return deleteFile(new File(path));
	}

	/**
	 * 删除指定路径的文件或文件夹
	 * @param file
	 * @return
	 */
	public static boolean delete(File file) {
		if (file == null) {
			return false;
		}
		if (file.exists()) {
			return file.delete();
		}
		return false;
	}

	/**
	 * 删除文件夹
	 * @param file
	 * @return
	 */
	public static boolean deleteDir(File file) {
		if (file == null || !file.exists()) {
			return false;
		}
		if (file.isFile()) {
			return file.delete();
		}
		File[] files = file.listFiles();
		if (files == null || files.length == 0) {
			//目录下无文件，直接删除目录
			return file.delete();
		}
		for (File childFile : file.listFiles()) {
			if (childFile.isDirectory()) {
				//递归删除
				deleteDir(file);
			}
			childFile.delete();
		}
		return file.delete();
	}

	/**
	 * @descriptoin	创建文件夹目录
	 * @author	ww
	 * @return path  路径
	 */
	public static boolean mkdirs(String path) {
		if (TextUtils.isEmpty(path)) {
			return false;
		}
		File folder = new File(path);
		return mkdirs(folder);
	}

	/**
	 * @descriptoin	创建文件夹目录
	 * @author	ww
	 * @return path  路径
	 */
	public static boolean mkdirs(File dir) {
		if (dir == null) {
			return false;
		}
		if (!dir.exists()) {
			return dir.mkdirs();
		}
		return false;
	}

	/**
	 * 列出指令路径下的所有文件
	 * @param dirPath
	 * @return
	 */
	public static File[] listFiles(String dirPath) {
		if (TextUtils.isEmpty(dirPath)) {
			return null;
		}
		File dir = new File(dirPath);
		return listFiles(dir);
	}

	/**
	 * 列出指令路径下的所有文件
	 * @param dir
	 * @return
	 */
	public static File[] listFiles(File dir) {
		if (dir == null) {
			return null;
		}
		if (dir.exists() && dir.isDirectory()) {
			return dir.listFiles();
		}
		return null;
	}

	/**
	 * 保存Bitmap为JPEG文件
	 * @param photoBitmap
	 * @param absPath
	 * @param quality 0-100
	 * @return
	 */
	public static boolean bitmap2JPEG(Bitmap photoBitmap, String absPath, int quality) {
		return bitmap2File(photoBitmap, new File(absPath), Bitmap.CompressFormat.JPEG, quality);
	}

	/**
	 * 保存Bitmap为PNG文件
	 * @param photoBitmap
	 * @param absPath
	 * @param quality 0-100
	 * @return
	 */
	public static boolean bitmap2PNG(Bitmap photoBitmap, String absPath, int quality) {
		return bitmap2File(photoBitmap, new File(absPath), Bitmap.CompressFormat.PNG, quality);
	}

	/**
	 * 保存Bitmap为WEBP文件
	 * @param photoBitmap
	 * @param absPath
	 * @param quality 0-100
	 * @return
	 */
	public static boolean bitmap2WEBP(Bitmap photoBitmap, String absPath, int quality) {
		return bitmap2File(photoBitmap, new File(absPath), Bitmap.CompressFormat.WEBP, quality);
	}

	/**
	 * 保存Bitmap为JPEG文件
	 * @param photoBitmap
	 * @param absPath
	 * @return
	 */
	public static boolean bitmap2JPEG(Bitmap photoBitmap, String absPath) {
		return bitmap2File(photoBitmap, new File(absPath), Bitmap.CompressFormat.JPEG, 100);
	}

	/**
	 * 保存Bitmap为PNG文件
	 * @param photoBitmap
	 * @param absPath
	 * @return
	 */
	public static boolean bitmap2PNG(Bitmap photoBitmap, String absPath) {
		return bitmap2File(photoBitmap, new File(absPath), Bitmap.CompressFormat.PNG, 100);
	}

	/**
	 * 保存Bitmap为WEBP文件
	 * @param photoBitmap
	 * @param absPath
	 * @return
	 */
	public static boolean bitmap2WEBP(Bitmap photoBitmap, String absPath) {
		return bitmap2File(photoBitmap, new File(absPath), Bitmap.CompressFormat.WEBP, 100);
	}

	/**
	 * 获取某个文件的大小
	 * @param filePath
	 * @return
	 */
	public static long fileLength(String filePath) {
		if (TextUtils.isEmpty(filePath)) {
			return 0;
		}
		File file = new File(filePath);
		return fileLength(file);
	}

	/**
	 * 获取某个文件的大小
	 * @param file
	 * @return
	 */
	public static long fileLength(File file) {
		if (file != null && file.exists() && file.isFile()) {
			return file.length();
		}
		return 0;
	}

	/**
	 * 获取某个文件夹下所有文件的大小
	 * @param dir
	 * @return
	 */
	public static long dirLength(File dir) {
		if (dir == null) {
			return 0;
		}
		if (!dir.exists()) {
			return 0;
		}
		if (dir.isFile()) {
			return fileLength(dir);
		}
		File[] files = dir.listFiles();
		long sum = 0;
		for (File file : files) {
			sum += fileLength(file);
		}
		return sum;
	}

	/**
	 * 某个文件是否以指定后缀结尾
	 * @param file
	 * @param suffix 后缀 比如".txt",".jpg",".png"
	 */
	public static boolean checkSuffix(File file, String suffix) {
		if (file == null || TextUtils.isEmpty(suffix) || !file.exists() || file.isDirectory()) {
			return false;
		}
		String fileName = file.getName();
		return fileName.substring(fileName.lastIndexOf(".")).equals(suffix);
	}

	/**
	 * 保存Bitmap为文件
	 * @param photoBitmap
	 * @param file
	 * @param quality 0-100
	 * @return
	 */
	public static boolean bitmap2File(Bitmap photoBitmap, File file, Bitmap.CompressFormat format, int quality) {
		if (photoBitmap == null || file == null) {
			return false;
		}
		if (!checkSDCardAvailable()) {
			return false;
		}
		createNewFile(file);
		FileOutputStream fileOutputStream = null;
		try {
			fileOutputStream = new FileOutputStream(file);
			if (photoBitmap.compress(format, quality, fileOutputStream)) {
				fileOutputStream.flush();
				return true;
			}
		} catch (FileNotFoundException e) {
			file.delete();
			e.printStackTrace();
		} catch (IOException e) {
			file.delete();
			e.printStackTrace();
		} finally {
			closeStream(fileOutputStream);
		}
		return false;
	}

	/**
	 * 将文件路径转化为Uri格式，如"file:///tmp/android.txt"
	 * @param context
	 * @param file
	 * @return
	 */
	public static Uri file2Uri(Context context, File file) {
		if (context == null || file == null) {
			return null;
		}
		Uri uri;
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
			uri = FileProvider.getUriForFile(context.getApplicationContext(), context.getApplicationInfo().processName, file);
		} else {
			uri = Uri.fromFile(file);
		}
		return uri;
	}

	/**
	 * Check the SD card
	 *
	 * @return 是否获能获取到SD卡
	 */
	public static boolean checkSDCardAvailable() {
		return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
	}

	/**
	 * 通过Uri获取Bitmap
	 * @param context
	 * @param uri
	 * @return
	 */
	public static Bitmap getBitmapByUri(Context context, Uri uri) {
		Bitmap bitmap = null;
		try {
			bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return bitmap;
	}

	/**
	 * 判断当前的文件是否是图片
	 * @param file
	 * @return
	 */
	public static boolean isImageFile(File file) {
		if (file == null || file.isDirectory()) {
			return false;
		}
		final String[] suffixes = new String[] { "jpg", "png", "gif", "jpeg", "bmp" };
		for (String suffix : suffixes) {
			if (checkSuffix(file, suffix)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 创建新的文件，如果存在则会删除重新创建，如果路径中包含有不存在的文件夹路径会自动创建文件夹
	 * @author ww
	 * @param file
	 * @return
	 */
	public static boolean createNewFile(File file) {
		if (file == null) {
			return false;
		}
		if (file.exists()) {
			file.delete();
		} else {
			if (!file.getParentFile().exists()) {
				file.getParentFile().mkdirs();
			}
		}
		try {
			return file.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 检测文件是否存在，存在则则直接返回，不存在则直接创建文件
	 * @author ww
	 * @param file
	 * @return
	 */
	public static File checkFile(File file) {
		if (file == null) {
			return null;
		}
		if (file.exists()) {
			return file;
		}
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		try {
			file.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		return file;
	}

	/**
	 * 文件拷贝
	 * @param srcPath
	 * @param destPath
	 */
	public static boolean copyFile(String srcPath, String destPath) {
		if (TextUtils.isEmpty(srcPath) || TextUtils.isEmpty(destPath)) {
			return false;
		}
		File srcFile = new File(srcPath);
		if (!srcFile.exists() || srcFile.isDirectory()) {
			return false;
		}
		File destFile = new File(destPath);
		if (!createNewFile(destFile)) {
			return false;
		}
		final int size = 8 * 1024;
		FileInputStream in = null;
		FileOutputStream out = null;
		try {
			in = new FileInputStream(srcFile);
			out = new FileOutputStream(destFile);
			byte[] buffer = new byte[size];
			int bytesRead = -1;
			while ((bytesRead = in.read(buffer)) != -1) {
				out.write(buffer, 0, bytesRead);
			}
			out.flush();
			return true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeStream(in);
			closeStream(out);
		}
		return false;
	}

	/**
	 * 复制整个文件夹内容
	 *
	 * @param oldPath String 原文件路径
	 * @param newPath String 复制后路径
	 * @return boolean
	 */
	public static void copyFolder(String oldPath, String newPath) {
		(new File(newPath)).mkdirs(); //如果文件夹不存在 则建立新文件夹
		File a = new File(oldPath);
		String[] file = a.list();
		try {
			File temp = null;
			for (int i = 0; i < file.length; i++) {
				if (oldPath.endsWith(File.separator)) {
					temp = new File(oldPath + file[i]);
				} else {
					temp = new File(oldPath + File.separator + file[i]);
				}
				if (temp.isFile()) {
					FileInputStream input = new FileInputStream(temp);
					FileOutputStream output = new FileOutputStream(newPath + "/" + (temp.getName()));
					byte[] b = new byte[1024 * 5];
					int len;
					while ((len = input.read(b)) != -1) {
						output.write(b, 0, len);
					}
					output.flush();
					output.close();
					input.close();
				}
				if (temp.isDirectory()) {//如果是子文件夹
					copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i]);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 压缩一个文件
	 *
	 * @param srcFilePath 需要压缩文件的路径
	 * @param zipFilePath 压缩后文件的路径
	 * @throws IOException 当解压缩过程出错时抛出
	 */
	public static void zipFolder(String srcFilePath, String zipFilePath) throws Exception {
		// 创建Zip包
		ZipOutputStream outZip = new ZipOutputStream(new FileOutputStream(zipFilePath));
		// 打开要输出的文件
		File file = new File(srcFilePath);
		// 压缩
		zipFiles(file.getParent() + File.separator, file.getName(), outZip);
		// 完成,关闭
		outZip.finish();
		outZip.close();
	}

	private static void zipFiles(String folderPath, String filePath, ZipOutputStream zipOut) throws Exception {
		if (zipOut == null) {
			return;
		}
		File file = new File(folderPath + filePath);
		// 判断是不是文件
		if (file.isFile()) {
			ZipEntry zipEntry = new ZipEntry(filePath);
			FileInputStream inputStream = new FileInputStream(file);
			zipOut.putNextEntry(zipEntry);
			int len;
			byte[] buffer = new byte[100000];
			while ((len = inputStream.read(buffer)) != -1) {
				zipOut.write(buffer, 0, len);
			}
			inputStream.close();
			zipOut.closeEntry();
		} else {
			// 文件夹的方式,获取文件夹下的子文件
			String fileList[] = file.list();
			// 如果没有子文件, 则添加进去即可
			if (fileList.length <= 0) {
				ZipEntry zipEntry = new ZipEntry(filePath + File.separator);
				zipOut.putNextEntry(zipEntry);
				zipOut.closeEntry();
			}
			// 如果有子文件, 遍历子文件
			for (int i = 0; i < fileList.length; i++) {
				zipFiles(folderPath, filePath + File.separator + fileList[i], zipOut);
			}
		}
	}

	/**
	 * read file
	 *
	 * @param charsetName The name of a supported {@link java.nio.charset.Charset
	 *                    </code>charset<code>}
	 * @return if file not exist, return null, else return content of file
	 */
	public static String readFile(File file, Charset charsetName) {
		if (file == null || !file.exists() || file.isDirectory()) {
			return null;
		}
		StringBuilder stringBuilder = new StringBuilder();
		BufferedReader reader = null;
		try {
			InputStreamReader is = new InputStreamReader(new FileInputStream(file), charsetName);
			reader = new BufferedReader(is);
			String line = null;
			while ((line = reader.readLine()) != null) {
				stringBuilder.append(line + "\r\n");
			}
			return stringBuilder.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeStream(reader);
		}
		return null;
	}

	/**
	 * UTF-8编码方式读取字符串
	 * @param file
	 * @return
	 */
	public static String readFile(File file) {
		return readFile(file, StandardCharsets.UTF_8);
	}

	/**
	 * 写入文件
	 * 断点续传
	 *
	 * @param in
	 * @param file
	 */
	public static boolean writeFile(InputStream in, File file) {
		if (in == null) {
			return false;
		}
		if (file == null || file.isDirectory()) {
			return false;
		}
		if (!createNewFile(file)) {
			return false;
		}
		RandomAccessFile savedFile = null;
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		long lastPos = file.length();
		try {
			savedFile = new RandomAccessFile(file, "rw");
			savedFile.seek(lastPos);
			byte[] buffer = new byte[1024 * 8];
			int len = -1;
			while ((len = in.read(buffer)) != -1) {
				savedFile.write(buffer, 0, len);
			}
			return true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeStream(in);
		}
		return false;
	}

	/**
	 * 将字符串写入文件
	 * @param path
	 * @param result
	 */
	public static boolean writeString2File(String path, String result) {
		if (TextUtils.isEmpty(path)) {
			return false;
		}
		if (!createNewFile(new File(path))) {
			return false;
		}
		FileWriter fileWriter = null;
		try {
			fileWriter = new FileWriter(path, true);
			fileWriter.write(result);
			fileWriter.flush();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeStream(fileWriter);
		}
		return false;
	}

	/**
	 * 读取文件中每行添加到集合
	 * @param path
	 * @return
	 */
	public static ArrayList<String> readLine2List(String path) {
		BufferedReader bufferedReader = null;
		ArrayList<String> arrayList = new ArrayList();
		try {
			bufferedReader = new BufferedReader(new FileReader(path));
			String line = null;
			while ((line = bufferedReader.readLine()) != null) {
				arrayList.add(line);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeStream(bufferedReader);
		}
		return arrayList;
	}

	/**
	 * 关闭输入、输出流
	 * @param closeable
	 */
	private static void closeStream(Closeable closeable) {
		StreamUtil.closeStream(closeable);
	}
}
